package com.sukaiyi.giteeideaplugin.utils;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.PlainTextFileType;
import com.sukaiyi.giteeideaplugin.misc.TriConsumer;

import javax.swing.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;

/**
 * @author sukaiyi
 * @date 2020/07/06
 */
public class FileTypeUtils {

    private static final Logger logger = Logger.getInstance(FileTypeUtils.class);

    private FileTypeUtils() {

    }

    public static final Map<String, FileType> FILE_TYPE_MAP;

    static {
        FILE_TYPE_MAP = new HashMap<>();
        Function<String, Object> defaultFunGetFileType = fileTypeClass -> ReflectUtils.getStaticFieldValue(fileTypeClass, "INSTANCE");

        BiConsumer<String, Function<String, ?>> singleFileTypeConsumer = (fileTypeClass, valueMapper) -> {
            Object instance = valueMapper.apply(fileTypeClass);
            if (instance instanceof FileType) {
                FileType fileType = (FileType) instance;
                FILE_TYPE_MAP.put(fileType.getDefaultExtension(), fileType);
            }
        };

        BiConsumer<String, Function<String, ?>> multiFileTypeConsumer = (fileTypeClass, valueMapper) -> {
            Object collection = valueMapper.apply(fileTypeClass);
            if (collection instanceof Collection) {
                Collection<?> fileTypes = (Collection<?>) collection;
                fileTypes.stream().filter(ins -> ins instanceof FileType).map(ins -> (FileType) ins).forEach(fileType -> {
                    FILE_TYPE_MAP.put(fileType.getDefaultExtension(), fileType);
                });
            }
        };

        TriConsumer<String, Function<String, String>, Function<String, ?>> keyFileTypeConsumer = (fileTypeClass, keyMapper, valueMapper) -> {
            Object value = valueMapper.apply(fileTypeClass);
            if (!(value instanceof FileType)) {
                return;
            }
            FileType fileType = (FileType) value;
            String key = keyMapper.apply(fileTypeClass);
            FILE_TYPE_MAP.put(key, fileType);
        };

        singleFileTypeConsumer.accept("com.intellij.ide.highlighter.JavaFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.json.JsonFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.json.json5.Json5FileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.ide.highlighter.HtmlFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.ide.highlighter.XHtmlFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.ide.highlighter.XmlFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.ide.highlighter.DTDFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.spellchecker.DictionaryFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.openapi.vcs.changes.ignore.lang.IgnoreFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.ide.highlighter.JShellFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("org.jetbrains.lang.manifest.ManifestFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.ide.highlighter.ModuleFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.openapi.fileTypes.PlainTextFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.ide.highlighter.ProjectFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("org.intellij.lang.regexp.RegExpFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("org.intellij.plugins.relaxNG.compact.RncFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.lang.javascript.linter.jscs.config.JscsConfigFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.lang.properties.PropertiesFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("org.jetbrains.yaml.YAMLFileType", fileTypeClass -> ReflectUtils.getStaticFieldValue(fileTypeClass, "YML"));
        multiFileTypeConsumer.accept("org.jetbrains.plugins.groovy.GroovyFileType", fileTypeClass -> ReflectUtils.getStaticFieldValue(fileTypeClass, "GROOVY_FILE_TYPES"));

        singleFileTypeConsumer.accept("com.intellij.sql.SqlFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.database.csv.CsvFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.lang.javascript.JavaScriptFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.lang.javascript.TypeScriptFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.lang.javascript.TypeScriptJSXFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.javascript.nodejs.YarnLockFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.lang.javascript.FlowJSFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.lang.javascript.linter.jshint.config.JSHintConfigFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.lang.ecmascript.JSXHarmonyFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.lang.ecmascript6.ES6FileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.psi.css.CssFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("org.intellij.plugins.markdown.lang.MarkdownFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("com.intellij.javascript.jest.JestSnapshotFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("org.intellij.images.fileTypes.impl.SvgFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("org.intellij.lang.batch.fileTypes.BatchFileType", fileTypeClass -> ReflectUtils.getStaticFieldValue(fileTypeClass, "BATCH_FILE_TYPE"));
        singleFileTypeConsumer.accept("com.intellij.sh.ShFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("org.jetbrains.kotlin.idea.KotlinFileType", defaultFunGetFileType);
        singleFileTypeConsumer.accept("org.jetbrains.kotlin.idea.KotlinModuleFileType", defaultFunGetFileType);

        keyFileTypeConsumer.accept(
                "com.intellij.docker.dockerFile.DockerFileType",
                fileTypeClass -> "Dockerfile",
                fileTypeClass -> ReflectUtils.getStaticFieldValue(fileTypeClass, "DOCKER_FILE_TYPE")
        );
    }

    private static String getSuffix(String name) {
        int lastDotIndex = name.lastIndexOf('.');
        if (lastDotIndex == -1) {
            return name;
        } else {
            return name.substring(lastDotIndex + 1);
        }
    }

    private static String getSimpleName(String name) {
        int lastSepIndex = name.lastIndexOf('/');
        if (lastSepIndex == -1) {
            return name;
        } else {
            return name.substring(lastSepIndex + 1);
        }
    }

    public static Icon getIconForName(String name) {
        return getFileTypeForName(name).getIcon();
    }

    public static Icon getIconForSuffix(String suffix) {
        return getFileTypeForSuffix(suffix).getIcon();
    }

    public static FileType getFileTypeForName(String name) {
        // 绝大多数情况可以用后缀名匹配
        FileType type = FILE_TYPE_MAP.get(getSuffix(name));
        if (type == null) {
            // 没匹配到时，用完全的文件名匹配
            String simpleName = getSimpleName(name);
            type = FILE_TYPE_MAP.getOrDefault(simpleName, PlainTextFileType.INSTANCE);
        }
        return type;
    }

    public static FileType getFileTypeForSuffix(String suffix) {
        return FILE_TYPE_MAP.getOrDefault(suffix, PlainTextFileType.INSTANCE);
    }

}
